export class LayerManager {
  constructor(id, map) {
    this._id = id
    this._map = map
    this._basemapLayers = []
    this._layers = []
    this._eventListener = new Map()
  }

  get basemapLayers() {
    return this._basemapLayers
  }

  get layers() {
    return this._layers
  }

  on(type, callback) {
    if (this._eventListener.has(type)) {
      this._eventListener.get(type)?.push(callback)
    } else {
      this._eventListener.set(type, [callback])
    }
  }

  off(type, callback) {
    if (this._eventListener.has(type)) {
      if (callback) {
        const functionList = this._eventListener.get(type)
        if (functionList) {
          const index = functionList.findIndex((item) => item === callback)
          if (index !== -1) {
            functionList.splice(index, 1)
          }
        }
      } else {
        this._eventListener.delete(type)
      }
    }
  }

  fire(type, params) {
    if (this._eventListener.has(type)) {
      this._eventListener.get(type)?.forEach((fn) => {
        fn(params)
      })
    }
  }

  /**
   * 添加图层
   */
  async addLayer(data, autoFly = true) {
    const heightOffset = data.heightOffset || 0
    const item = {
      id: data.id,
      name: data.name,
      type: data.type,
    }
    switch (data.type) {
      case 'qingxie':
        item.layers = [
          await this.generalQingxieLayer(data.id, data.url, heightOffset),
        ]
        break
      case 'baimo':
        item.layers = [await this.generalBaiMoLayer(data.id, data.url)]
        break
      case 'weilan':
        item.layers = [this.generalWeilanLayer(data.positions)]
        break
      case 'billboard':
        item.layers = this.generalBillboard(data.id, data.dataList)
        break
      // case 'billboard2':
      //   item.layers = this.generalBillboard2(data.id, data.dataList)
      //   break
      case 'areaBillboard':
        item.layers = this.generalAreaBillboard(data.id, data.dataList)
        break
      case 'park_range':
        item.layers = await this.generalParkRange(data.id, data.url, autoFly)
        break
    }
    this.layers.push(item)
    this.fire('add', item)
  }

  async generalQingxieLayer(id, url, heightOffset) {
    const tileset = await Cesium.Cesium3DTileset.fromUrl(url)

    if (heightOffset !== 0) {
      // 将3d tiles离地高度抬升100米
      let cartographic = Cesium.Cartographic.fromCartesian(
        tileset.boundingSphere.center,
      )
      let surface = Cesium.Cartesian3.fromRadians(
        cartographic.longitude,
        cartographic.latitude,
        0.0,
      )
      let offset = Cesium.Cartesian3.fromRadians(
        cartographic.longitude,
        cartographic.latitude,
        heightOffset,
      )
      let translation = Cesium.Cartesian3.subtract(
        offset,
        surface,
        new Cesium.Cartesian3(),
      )
      tileset.modelMatrix = Cesium.Matrix4.fromTranslation(translation)
    }

    this._map.scene.primitives.add(tileset)

    this._map.flyTo(tileset)
    return tileset
  }

  async generalBaiMoLayer(id, url) {
    const tileset = await Cesium.Cesium3DTileset.fromUrl(url)
    this._map.scene.primitives.add(tileset)

    tileset.style = new Cesium.Cesium3DTileStyle({
      color: {
        conditions: [
          [
            'true',
            id === 'tileset'
              ? "color('rgb(255,255,255)',1)"
              : "color('rgb(111,218,254)',1)",
          ],
        ],
        // conditions: [['true', "color('rgb(51,153,255)',1)"]],
      },
    })

    // 将定义好的着色器作用域建筑tilesets
    if (id !== 'tileset') {
      //   tileset.customShader = new Cesium.CustomShader({
      //     // 不考虑光照模型
      //     lightingModel: Cesium.LightingModel.UNLIT,
      //     // 修改片元着色器
      //     fragmentShaderText: `
      // void fragmentMain(FragmentInput fsInput, inout czm_modelMaterial material) {
      //     float _baseHeight = 0.0; // 物体的基础高度，需要修改成一个合适的建筑基础高度
      //     float _heightRange = 100.0; // 高亮的范围(_baseHeight ~ _baseHeight + _      heightRange) 默认是 0-60米
      //     float _glowRange = 300.0; // 光环的移动范围(高度)
      //     float vtxf_height = fsInput.attributes.positionMC.z-_baseHeight;
      //     float vtxf_a11 = fract(czm_frameNumber / 60.0) * 3.14159265 * 2.0;
      //     float vtxf_a12 = vtxf_height / _heightRange + sin(vtxf_a11) * 0.1;
      //     //  if (vtxf_height > 15.) {
      //     //     material.diffuse*= vec3(vtxf_a12, vtxf_a12, vtxf_a12);
      //     // }
      //     material.diffuse += material.normalEC;
      //     float vtxf_a13 = fract(czm_frameNumber / 60.0);
      //     float vtxf_h = clamp(vtxf_height / _glowRange, 0.0, 1.0);
      //     vtxf_a13 = abs(vtxf_a13 - 0.5) * 2.0;
      //     float vtxf_diff = step(0.005, abs(vtxf_h - vtxf_a13));
      //     material.diffuse += material.diffuse * (1.0 - vtxf_diff);
      // }
      // `,
      //   })
    }
    this._map.flyTo(tileset)
    return tileset
  }

  generalWeilanLayer(_positions) {
    const positions = []
    _positions.map((pos) => {
      positions.push(pos.lng, pos.lat)
    })

    return this._map.entities.add({
      name: '立体墙效果',
      wall: {
        positions: Cesium.Cartesian3.fromDegreesArray(positions),
        // 设置高度
        maximumHeights: new Array(_positions.length).fill(100),
        minimumHeights: new Array(_positions.length).fill(0),
        material: new Cesium.DynamicWallMaterialProperty({
          color: Cesium.Color.fromBytes(55, 25, 255).withAlpha(0.7),
          duration: 3000,
          viewer: this._map,
        }),
      },
    })
  }

  generalBillboard(id, dataList) {
    const entities = []
    dataList.forEach((data) => {
      let id = ''
      if (data.meta?.type === 'monitor') {
        id = `monitor__${data.id}`
      }
      const entity = this._map.entities.add({
        id: id || undefined,
        properties: new Cesium.PropertyBag(data),
        position: Cesium.Cartesian3.fromDegrees(...data.position),
        billboard: {
          verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
          image: data.img,
          scale: 0.8,
        },
        __data: id ? data : undefined,
      })
      entities.push(entity)
    })
    return entities
  }
  // generalBillboard2(id, dataList) {
  //   const entities = []
  //   dataList.forEach((data) => {
  //     const entity = this._map.entities.add({
  //       properties: new Cesium.PropertyBag(data),
  //       position: Cesium.Cartesian3.fromDegrees(...data.position),
  //       billboard: {
  //         verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
  //         image: data.img,
  //         scale: 0.4,
  //       },
  //     })
  //     entities.push(entity)
  //   })
  //   return entities
  // }

  generalAreaBillboard(id, dataList) {
    const entities = []
    const heightReference = Cesium.HeightReference.RELATIVE_TO_GROUND
    dataList.forEach((data) => {
      const entity = this._map.entities.add({
        properties: new Cesium.PropertyBag(data),
        position: Cesium.Cartesian3.fromDegrees(...data.position),
        billboard: {
          verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
          image: data.img,
          scale: 0.4,
          pixelOffset: new Cesium.Cartesian2(0, -40),
          heightReference: heightReference,
          disableDepthTestDistance: Number.POSITIVE_INFINITY,
        },
      })
      const entity1 = this._map.entities.add({
        properties: new Cesium.PropertyBag(data),
        position: Cesium.Cartesian3.fromDegrees(...data.position),
        billboard: {
          verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
          image: data.img1,
          scale: 0.5,
          pixelOffset: new Cesium.Cartesian2(0, -100),
          heightReference: heightReference,
          disableDepthTestDistance: Number.POSITIVE_INFINITY,
        },
      })
      const entity2 = this._map.entities.add({
        properties: new Cesium.PropertyBag(data),
        position: Cesium.Cartesian3.fromDegrees(...data.position),
        label: {
          text: data.label,
          font: 'Bold 32px MicroSoft YaHei',
          showBackground: false,
          scale: 0.5,
          fillColor: new Cesium.Color.fromCssColorString('#EFFBFF'), //设置文字填充的颜色
          outlineColor: new Cesium.Color.fromCssColorString('#EFFBFF'), //设置外框颜色
          outlineWidth: 0, //设置外框大小
          style: Cesium.LabelStyle.FILL_AND_OUTLINE, //填充方式，内外都填充
          verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
          pixelOffset: new Cesium.Cartesian2(0, -110),
          heightReference: heightReference,
          disableDepthTestDistance: Number.POSITIVE_INFINITY,
        },
      })
      entities.push(entity)
      entities.push(entity1)
      entities.push(entity2)
    })
    return entities
  }

  async generalParkRange(id, url, autoFly) {
    const entities = []
    const geojson = this._map.dataSources.add(
      Cesium.GeoJsonDataSource.load(url, {
        clampToGround: true,
      }),
    )
    await geojson.then((geojson) => {
      geojson.entities.values.forEach((entity) => {
        if (Cesium.defined(entity.polyline)) {
          entity.polyline.material = Cesium.Color.fromCssColorString('#ff0000')
        }
      })
      entities.push(geojson)
    })
    if (autoFly) {
      this._map.flyTo(geojson)
    }
    return entities
  }

  /**
   * 移除图层
   */
  removeLayer(data) {
    const index = this._layers.findIndex((item) => item.id === data.id)
    if (index !== -1) {
      this._removeLayer(data.id, data.type)
      this._layers.splice(index, 1)
      this.fire('remove', data.id)
    }
  }

  _removeLayer(id, type) {
    const current = this.layers.find((layer) => layer.id === id)
    if (current.layers) {
      switch (type) {
        case 'qingxie':
        case 'baimo':
          current.layers.forEach((primitive) => {
            this._map.scene.primitives.remove(primitive)
          })
          break
        case 'weilan':
        case 'billboard':
        // case 'billboard2':
        case 'areaBillboard':
          current.layers.forEach((entity) => {
            this._map.entities.remove(entity)
          })
          break
        case 'park_range':
          current.layers.forEach((entity) => {
            this._map.dataSources.remove(entity)
          })
          break
      }
    }
  }

  /**
   * 设置底图
   *
   * @param {string} id 底图id
   * @param {string} name 底图名称
   * @param {string} type 底图类型
   * @param {string} url 底图url
   */
  setBasemapLayer(id, name, type, url) {
    if (this._basemapLayers.length) {
      this.removeBasemapLayer(this._basemapLayers[0].id)
    }

    this._basemapLayers.push({
      id: id,
      name: name,
      type: type,
      url: url,
    })

    this._addBasemapLayer(id, type, url)
  }

  /**
   * 移除底图
   *
   * @param {string} id 底图id
   */
  removeBasemapLayer(id) {
    const index = this._basemapLayers.findIndex((item) => item.id === id)
    if (index !== -1) {
      this._removeBasemapLayer(id)
      this._basemapLayers.splice(index, 1)
    }
  }

  _addBasemapLayer(id, type, url) {
    const current = this._basemapLayers.find((layer) => layer.id === id)
    switch (type) {
      case '21': // WMTS
        current.layers = [this.generalTDTImageLayer(id, type, url)]
        break
      case '22': // XYZ
        let layer
        if (url.includes('{s}')) {
          layer = this._map.imageryLayers.addImageryProvider(
            new window.Cesium.UrlTemplateImageryProvider({
              url: url,
              subdomains: ['t0', 't1', 't2', 't3', 't4', 't5', 't6', 't7'],
            }),
            0,
          )
        } else {
          layer = this._map.imageryLayers.addImageryProvider(
            new window.Cesium.UrlTemplateImageryProvider({
              url: url,
            }),
            0,
          )
        }
        current.layers = [layer]
        break
      case '23': // MVT
        // this._map.scene.addVectorTilesMap({
        //   url: url,
        //   format: 'mvt',
        //   viewer: this._map,
        // })
        break
      case '24': // WMS
      case '25': // ArcGIS
        break
      // case '26': //TDT
      //   current.layers = [this.generalTDTImageLayer(id, type, url)]
      //   break
      default:
        break
    }
  }

  generalTDTImageLayer(id, type, layerUrl) {
    const urlParams = new URLSearchParams(layerUrl)
    let tileMatrixSet = urlParams.get('tileMatrixSet')
    if (!tileMatrixSet) {
      const index = layerUrl.indexOf('_') + 1
      tileMatrixSet = layerUrl[index]
    }
    const tileMatrixSetID = tileMatrixSet === 'c' ? 'c' : 'GoogleMapsCompatible'
    const tilingScheme =
      tileMatrixSet === 'c' ? new Cesium.GeographicTilingScheme() : null
    let tileMatrixLabels = Array.from({ length: 18 }, (v, k) => k + 1 + '')
    if (tileMatrixSet === 'w') {
      tileMatrixLabels = null
    }
    const wmtsProvider = new Cesium.WebMapTileServiceImageryProvider({
      url: layerUrl,
      layer: 'tdtLayer',
      style: 'default',
      format: 'tiles',
      tileMatrixSetID,
      subdomains: ['t0', 't1', 't2', 't3', 't4', 't5', 't6', 't7'],
      tilingScheme,
      tileMatrixLabels,
      maximumLevel: 17,
    })
    // const wmtsLayer = new Cesium.ImageryLayer(wmtsProvider);
    return this._map.imageryLayers.addImageryProvider(wmtsProvider)
  }

  _removeBasemapLayer(id) {
    const current = this._basemapLayers.find((layer) => layer.id === id)
    if (current.layers) {
      current.layers.forEach((layer) => {
        this._map.imageryLayers.remove(layer)
      })
    }
  }
}
